package com.night.icm.service.base.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.night_enum.CompAssessProcessStatus;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.SimpleDataDTO;
import com.night.icm.model.base.StudentDTO;
import com.night.icm.model.core.UserDTO;
import com.night.icm.persistence.base.entity.Class;
import com.night.icm.persistence.base.entity.*;
import com.night.icm.persistence.base.entity.comprehensive_test.AcademicPoint;
import com.night.icm.persistence.base.entity.comprehensive_test.ComprehensiveScore;
import com.night.icm.persistence.base.entity.comprehensive_test.IdeologicalPoint;
import com.night.icm.persistence.base.entity.comprehensive_test.StylisticPoint;
import com.night.icm.persistence.base.repository.*;
import com.night.icm.persistence.base.repository.comprehensive_test.AcademicPointRepository;
import com.night.icm.persistence.base.repository.comprehensive_test.ComprehensiveScoreRepository;
import com.night.icm.persistence.base.repository.comprehensive_test.IdeologicalPointRepository;
import com.night.icm.persistence.base.repository.comprehensive_test.StylisticPointRepository;
import com.night.icm.persistence.business.entity.AcademicProgress;
import com.night.icm.persistence.business.entity.GraduationCreditRequirements;
import com.night.icm.persistence.business.reporsitory.AcademicProgressRepository;
import com.night.icm.persistence.core.entity.User;
import com.night.icm.service.base.mapper.StudentMapper;
import com.night.icm.service.core.mapper.UserMapper;
import com.night.icm.service.core.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * StudentServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/1/29
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class StudentServiceImpl implements StudentService {

    private final StudentMapper studentMapper;
    private final StudentRepository studentRepository;
    private final UserService userService;
    private final UserMapper userMapper;
    private final AcademyRepository academyRepository;
    private final ProfessionRepository professionRepository;
    private final ClassRepository classRepository;
    private final AcademicProgressRepository academicProgressRepository;
    private final ComprehensiveScoreRepository comprehensiveScoreRepository;
    private final AcademicPointRepository academicPointRepository;
    private final IdeologicalPointRepository ideologicalPointRepository;
    private final StylisticPointRepository stylisticPointRepository;
    private final StudentDetailRepository studentDetailRepository;


    @Autowired
    public StudentServiceImpl(StudentMapper studentMapper, StudentRepository studentRepository, UserService userService, UserMapper userMapper, AcademyRepository academyRepository, ProfessionRepository professionRepository, ClassRepository classRepository, AcademicProgressRepository academicProgressRepository, ComprehensiveScoreRepository comprehensiveScoreRepository, AcademicPointRepository academicPointRepository, IdeologicalPointRepository ideologicalPointRepository, StylisticPointRepository stylisticPointRepository, StudentDetailRepository studentDetailRepository) {
        this.studentMapper = studentMapper;
        this.studentRepository = studentRepository;
        this.userService = userService;
        this.userMapper = userMapper;
        this.academyRepository = academyRepository;
        this.professionRepository = professionRepository;
        this.classRepository = classRepository;
        this.academicProgressRepository = academicProgressRepository;
        this.comprehensiveScoreRepository = comprehensiveScoreRepository;
        this.academicPointRepository = academicPointRepository;
        this.ideologicalPointRepository = ideologicalPointRepository;
        this.stylisticPointRepository = stylisticPointRepository;
        this.studentDetailRepository = studentDetailRepository;
    }

    /**
     * 分页查询学生信息
     *
     * @param page         页号，从0开始
     * @param size         每页记录条数
     * @param sort         排序字段，例如：字段1,asc,字段2,desc
     * @param code         学生学号
     * @param name         学生姓名
     * @param grade        年级，即入学年份
     * @param academyId    所属学院
     * @param professionId 所属专业
     * @param classId      所属班级
     * @return 学生信息
     */
    @Override
    public PageDataDTO<StudentDTO> findOnePage(int page, int size, String sort, String code, String name, String grade, String academyId, String professionId, String classId) {
        PredicateBuilder<Student> pb = Specifications.<Student>and()
                .like(StringUtils.isNotBlank(code), "code", "%" + code + "%")
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
                .eq(StringUtils.isNotBlank(grade), "grade", grade)
                .eq(StringUtils.isNotBlank(academyId), "academy.id", academyId)
                .eq(StringUtils.isNotBlank(professionId), "profession.id", professionId)
                .eq(StringUtils.isNotBlank(classId), "aClass.id", classId);
        Page<Student> page1 = this.studentRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<StudentDTO> dtos = this.studentMapper.toList(page1.getContent());
        return PageDataUtil.toPageData(page1, dtos);
    }

    /**
     * 新增学生信息
     *
     * @param studentDTO   学生信息
     * @return 学生信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentDTO create(StudentDTO studentDTO) {
        // 保存学生信息
        Student student = this.studentMapper.toEntity(studentDTO);
        StudentDetail studentDetail = student.getStudentDetail();
        student.setStudentDetail(null);
        student = this.studentRepository.save(student);
        // 新建学生登录用户——》封装一个创建用户的方法
        User user = this.createUser(studentDTO.getCode(), studentDTO.getIsClassEvaluationAdmin());
        // 获取学院
        Academy academy = this.getAcademyById(studentDTO.getAcademyId());
        // 获取专业
        Profession profession = this.getProfessionById(studentDTO.getProfessionId());
        // 获取班级
        Class aClass = this.getClassById(studentDTO.getClassId());

        // 分步保存学生的关联信息
        student.setUser(user);
        student = this.studentRepository.save(student);
        student.setAcademy(academy);
        student = this.studentRepository.save(student);
        student.setProfession(profession);
        student = this.studentRepository.save(student);
        student.setAClass(aClass);
        student = this.studentRepository.save(student);

        // 获取学生所在专业的毕业学分最低要求，并创建学生学业进展
        GraduationCreditRequirements graduationCreditRequirements = profession.getGraduationCreditRequirements();
        AcademicProgress academicProgress = new AcademicProgress();

        // 初始化学生学业最低学分要求
        academicProgress.setCompulsoryCredit(graduationCreditRequirements.getCompulsoryCredit());
        academicProgress.setSubjectBasedElective(graduationCreditRequirements.getSubjectBasedElective());
        academicProgress.setProfessionElective(graduationCreditRequirements.getProfessionElective());
        academicProgress.setPublicElective(graduationCreditRequirements.getPublicElective());
        academicProgress.setPracticeCredit(graduationCreditRequirements.getPracticeCredit());
        academicProgress.setInnovationScore(graduationCreditRequirements.getInnovationScore());
        academicProgress.setGraduationInternship(graduationCreditRequirements.getGraduationInternship());
        academicProgress.setGraduationThesis(graduationCreditRequirements.getGraduationThesis());
        academicProgress.setTotal(graduationCreditRequirements.getTotal());
        academicProgress.setStudent(student);
        this.academicProgressRepository.save(academicProgress);

        // 保存学生详细信息
        this.studentDetailRepository.save(studentDetail);
        student.setStudentDetail(studentDetail);
        student = this.studentRepository.save(student);

        // 初始化学生每年的综合测评数据
        Integer studyYears = student.getStudyYears();
        Integer grade = student.getGrade();
        List<ComprehensiveScore> list = new ArrayList<>();
        int year = grade;
        for (int i = 0; i < studyYears; i++) {
            ComprehensiveScore comprehensiveScore = new ComprehensiveScore();
            AcademicPoint academicPoint = new AcademicPoint();
            academicPoint.setId(null);
            comprehensiveScore.setAcademicPoint(academicPoint);
            IdeologicalPoint ideologicalPoint = new IdeologicalPoint();
            ideologicalPoint.setId(null);
            comprehensiveScore.setIdeologicalPoint(ideologicalPoint);
            StylisticPoint stylisticPoint = new StylisticPoint();
            stylisticPoint.setId(null);
            comprehensiveScore.setStylisticPoint(stylisticPoint);
            comprehensiveScore.setYear(year);
            comprehensiveScore.setCompAssessProcessStatus(CompAssessProcessStatus.SELF_ASSESSMENT);
            comprehensiveScore.setComprehensiveScoreTotal(0.0);
            comprehensiveScore.setShowOrder(year);
            comprehensiveScore.setStudent(student);
            comprehensiveScore.setIsReport(false);
            list.add(comprehensiveScore);
            year += 1;
        }
        this.comprehensiveScoreRepository.saveAll(list);
        return this.studentMapper.toDTO(student);
    }

    /**
     * 根据id获取学院
     *
     * @param id 学院id
     * @return 学院
     */
    private Academy getAcademyById(String id) {
        Optional<Academy> optionalAcademy = this.academyRepository.findById(Long.valueOf(id));
        if (!optionalAcademy.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalAcademy.get();
    }

    /**
     * 根据id获取专业
     *
     * @param id 专业id
     * @return 专业
     */
    private Profession getProfessionById(String id) {
        Optional<Profession> optionalProfession = this.professionRepository.findById(Long.valueOf(id));
        if (!optionalProfession.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalProfession.get();
    }

    /**
     * 根据id获取班级
     *
     * @param id 班级id
     * @return 班级
     */
    private Class getClassById(String id) {
        Optional<Class> optionalClass = this.classRepository.findById(Long.valueOf(id));
        if (!optionalClass.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalClass.get();
    }

    /**
     * 新增学生时创建学生用户
     *
     * @param studentCode 学生学号
     * @param isClassEvaluationAdmin 是否班级测评管理员
     */
    private User createUser(String studentCode, Boolean isClassEvaluationAdmin) {
        UserDTO userDTO = new UserDTO();
        // 学号作为登录用户名
        userDTO.setUsername(studentCode);
        // 登录密码默认6个8
        userDTO.setPassword("888888");
        // 设置学生身份权限
        userDTO.setRole(Boolean.TRUE.equals(isClassEvaluationAdmin) ? "ROLE_CLASS_EVALUATION_ADMIN" : "ROLE_STUDENT");
        UserDTO dto = this.userService.createUser(userDTO);
        return this.userMapper.toEntity(dto);
    }

    /**
     * 根据id删除学生
     *
     * @param id 学生id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        this.studentRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 更新学生信息
     *
     * @param id         学生id
     * @param studentDTO 学生信息
     * @return 学生信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentDTO update(String id, StudentDTO studentDTO) {
        Student student = this.getOne(id);
        this.studentMapper.updateEntity(studentDTO, student);
        if (!student.getAcademy().getId().equals(Long.valueOf(studentDTO.getAcademyId()))) {
            Academy academy = this.getAcademyById(studentDTO.getAcademyId());
            student.setAcademy(academy);
        }
        if (!student.getProfession().getId().equals(Long.valueOf(studentDTO.getProfessionId()))) {
            Profession profession = this.getProfessionById(studentDTO.getProfessionId());
            student.setProfession(profession);
        }
        if (!student.getAClass().getId().equals(Long.valueOf(studentDTO.getClassId()))) {
            Class aClass = this.getClassById(studentDTO.getClassId());
            student.setAClass(aClass);
        }
        this.studentRepository.save(student);
        // 判断是否班级综测管理员
        UserDTO userDTO = this.userService.findByName(student.getCode());
        userDTO.setRole(Boolean.TRUE.equals(studentDTO.getIsClassEvaluationAdmin()) ? "ROLE_CLASS_EVALUATION_ADMIN" : "ROLE_STUDENT");
        this.userService.update(userDTO.getId(), userDTO);
        return this.studentMapper.toDTO(student);
    }

    /**
     * 根据id查找学生
     *
     * @param id 学生id
     * @return 学生
     */
    @Override
    public StudentDTO findById(String id) {
        Student student = this.getOne(id);
        return this.studentMapper.toDTO(student);
    }

    /**
     * 根据id获取学生
     *
     * @param id 学生id
     * @return 学生
     */
    private Student getOne(String id) {
        Optional<Student> optionalStudent = this.studentRepository.findById(Long.valueOf(id));
        if (!optionalStudent.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalStudent.get();

    }

    /**
     * 查找所有学生信息，可选择排序
     *
     * @param param   排序参数
     * @param pattern 排序模式: asc/desc
     * @return 学生信息
     */
    @Override
    public List<StudentDTO> findAll(String param, String pattern) {
        String keyType = "asc";
        Sort sort;
        if (keyType.equals(pattern)) {
            sort = new Sort(Sort.Direction.ASC, param);
        } else {
            sort = new Sort(Sort.Direction.DESC, param);
        }
        List<Student> all = this.studentRepository.findAll(sort);
        return this.studentMapper.toList(all);
    }

    /**
     * 检查学生学号是否已存在
     *
     * @param code 学生code
     * @return 学号是否已存在
     */
    @Override
    public SimpleDataDTO<Boolean> checkCodeExist(String code) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        Student student = this.studentRepository.findByCode(code);
        simpleDataDTO.setData(student != null);
        return simpleDataDTO;
    }

    /**
     * 根据userId查找学生
     *
     * @param userId userId
     * @return 学生
     */
    @Override
    public StudentDTO findByUserId(String userId) {
        Student student = this.studentRepository.findByUserId(Integer.valueOf(userId));
        return this.studentMapper.toDTO(student);
    }

    /**
     * 统计学生数量
     *
     * @return 统计学生数量
     */
    @Override
    public Long countStudent() {
        return this.studentRepository.count();
    }

}